package org.ecloud.oauth.server.service.impl;

import java.util.Date;
import java.util.List;

import org.ecloud.base.identifier.IdGenerator;
import org.ecloud.oauth.constants.RedisKey;
import org.ecloud.oauth.exception.ExcessiveAttemptsException;
import org.ecloud.oauth.exception.ExpiredCredentialsException;
import org.ecloud.oauth.exception.IncorrectCredentialsException;
import org.ecloud.oauth.exception.ManyIncorrectCredentialsException;
import org.ecloud.oauth.exception.UnknownAccountException;
import org.ecloud.oauth.server.config.UserConfig;
import org.ecloud.oauth.server.entity.SecurityVo;
import org.ecloud.oauth.server.entity.UserVo;
import org.ecloud.oauth.server.mapper.LocalRowMapper;
import org.ecloud.oauth.server.service.BaseService;
import org.ecloud.oauth.server.service.IUserService;
import org.ecloud.redis.config.AppConfig;
import org.ecloud.redis.utils.RedisUtil;
import org.ecloud.utils.BeanUtil;
import org.ecloud.utils.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class UserServiceImpl extends BaseService implements IUserService {

	@Autowired
	private UserConfig config;
	@Autowired
	protected AppConfig appConfig;
	@Autowired
	private IdGenerator idGenerator;
	
	@Override
	public UserVo getByAccount(String account) {
		List<UserVo> users = jdbcTemplate.query(config.getSql(), new Object[]{account}, new LocalRowMapper<UserVo>(UserVo.class));
		
		if(BeanUtil.isNotEmpty(users)){
			return users.get(0);
		}
		
		return null;
	}

	@Override
	public UserVo login(String account, String password) {
		// 用户查询
		UserVo user = getByAccount(account);
		
		if(BeanUtil.isEmpty(user)){
			throw new UnknownAccountException("未知账号");
		}
		
		// 状态匹配
		config.verifyStatus(user.getStatus());
		
		// 密码匹配
		matchPassword(account, password, user);
		
		// 密码过期
		expriedPassword(user);
		
		return user;
	}

	/**
	 * 密码过期校验
	 *
	 * @param user 
	 */
	private void expriedPassword(UserVo user) {
		// 密码过期
		if(BeanUtil.isNotEmpty(config.getSecurity())){
			List<SecurityVo> securities = jdbcTemplate.query(config.getSecurity().getSql(), new LocalRowMapper<SecurityVo>(SecurityVo.class));
			if(BeanUtil.isNotEmpty(securities)){
				SecurityVo security = securities.get(0);
				
				int limit = security.getLimitTime();
				Date createTime = user.getCreatetime();
				Date updateTime = user.getUpdatetime();
				Date time = BeanUtil.isEmpty(updateTime) ? createTime : updateTime;
				Date exprieTime = DateUtil.addDays(time, limit);
				Date currentTime = new Date();
				
				if(DateUtil.compare(exprieTime, currentTime)){
					throw new ExpiredCredentialsException("密码过期，请修改密码后再登录");
				}
			}
		}
	}

	/**
	 * 密码匹配
	 *
	 * @param account
	 * @param password
	 * @param user 
	 */
	private void matchPassword(String account, String password, UserVo user) {
		// 密码加密
		password = config.encrypt(password);
		// 密码错误
		if(!user.getPassword().equals(password)){
			String key = appConfig.getRedisKey(RedisKey.LOGIN_RETRY, account);
			Integer realRetry = RedisUtil.redisTemplateInteger.opsForValue().get(key);
			realRetry = realRetry == null ? 0 : realRetry;
			int validRetry = config.getValidRetry();
			int lockRetry = config.getLock().getRetry();
			String lockMode = config.getLock().getMode();
			int lockTimeSecond = config.getLock().getTime();
			Date lockTime = new Date();
			Date unlockTime = new Date();
			
			realRetry += 1;
			RedisUtil.redisTemplateInteger.opsForValue().set(key, realRetry);
			// 第二天零点零分零秒过期
			Date date = getDate();
			RedisUtil.redisTemplateInteger.expireAt(key, date);
			
			if(realRetry >= lockRetry){
				// 密码错误多次，锁定用户
				String countSql = config.getLock().getCountSql();
				Integer count = jdbcTemplate.queryForObject(countSql, Integer.class, account);
				if(count != null && count > 0){
					String removeSql = config.getLock().getRemoveSql();
					jdbcTemplate.update(removeSql, account);
				}
				// 用户状态改为锁定
				String lockSql = config.getStatusInfo().getLockSql();
				jdbcTemplate.update(lockSql, config.getStatusInfo().getLocked(), user.getUid());
				// 用户登录限制数据添加，为自动解锁提供数据基础
				String sql = config.getLock().getSql();
				unlockTime = DateUtil.addSeconds(unlockTime, lockTimeSecond);
				jdbcTemplate.update(sql, idGenerator.getId(), account, lockMode, lockTime, unlockTime);
				throw new ExcessiveAttemptsException("多次登录失败，用户被锁定");
			} else if(realRetry >= validRetry) {
				// 密码错误多次，要求输入验证码
				throw new ManyIncorrectCredentialsException("多次登录失败，请输入验证码");
			} else {
				// 密码错误
				throw new IncorrectCredentialsException("用户名或密码错误");
			}
		}
	}

	/**
	 * 第二天零点零分零秒过期
	 *
	 * @return 
	 */
	private Date getDate() {
		Date date = new Date();
		date = DateUtil.addDays(date, 1);
		date = DateUtil.setHours(date, 0);
		date = DateUtil.setMinutes(date, 0);
		date = DateUtil.setSeconds(date, 0);
		date = DateUtil.setMilliseconds(date, 0);
		return date;
	}
	
}
